package org.springframework.howelly.services;

import java.text.ParseException;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.howelly.helpers.SearchCriteria;
import org.springframework.howelly.model.Categoria;
import org.springframework.howelly.model.Gasto;
import org.springframework.howelly.model.Obra;
import org.springframework.howelly.model.User;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

/**
 * A JPA-based implementation of the Obra Service. Delegates to a JPA entity manager to issue data access calls against
 * the backing repository. The EntityManager reference is provided by the managing container (Spring) automatically.
 */
@Service("obraService")
@Repository
public class JpaObraService implements ObraService {

    private EntityManager em;

    @PersistenceContext
    public void setEntityManager(EntityManager em) {
	this.em = em;
    }

    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    public List<Obra> findObras(SearchCriteria criteria) {
	String pattern = getSearchPattern(criteria);
	// make sure that is going to the DB for real data
	em.flush();
	em.clear();

	List<Obra> results = em.createQuery(
		"select h from Obra h where lower(h.name) like " + pattern + " or lower(h.city) like " + pattern
			+ " or lower(h.zip) like " + pattern + " or lower(h.address) like " + pattern + " order by h."
			+ criteria.getSortBy()).setMaxResults(criteria.getPageSize()).setFirstResult(
		criteria.getPage() * criteria.getPageSize()).getResultList();

	return results;
    }

    @Transactional(readOnly = true)
    public Obra findObrasById(Long id) {
	return em.find(Obra.class, id);

    }

    @Transactional
    public Obra createObra(Obra newObra) {
	if (newObra.getName().equals(""))
	    return new Obra();
	for (Categoria categoria : newObra.getCategorias()) {
	    categoria.setObra(newObra);
	}
	em.persist(newObra);
	return newObra;

    }

    @Transactional
    public Obra updateObra(Obra newObra) {
	if (newObra.getName().equals(""))
	    return new Obra();
	for (Categoria categoria : newObra.getCategorias()) {
	    categoria.setObra(newObra);
	}
	em.merge(newObra);
	return newObra;

    }

    @Transactional
    public boolean deleteObra(Obra obraToDelete) {
	Obra obra = em.find(Obra.class, obraToDelete.getId());
	if (obra != null) {
	    em.remove(obra);
	    em.flush();
	    return true;
	}
	return false;
    }

    @Transactional(readOnly = true)
    public Gasto createBooking(Long obraId, String username) throws ParseException {
	Obra obra = em.find(Obra.class, obraId);
	User user = findUser(username);
	Gasto gasto = new Gasto(obra, user);
	em.persist(gasto);
	return gasto;
    }

    // helpers
    private String getSearchPattern(SearchCriteria criteria) {
	if (StringUtils.hasText(criteria.getSearchString())) {
	    return "'%" + criteria.getSearchString().toLowerCase().replace('*', '%') + "%'";
	} else {
	    return "'%'";
	}
    }

    private User findUser(String username) {
	return (User) em.createQuery("select u from User u where u.username = :username").setParameter("username",
		username).getSingleResult();
    }

}